home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
LIBRARY
/
CMPLTPAS
/
GAMER.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-08-01
|
11KB
|
275 lines
;===========================================================================
;
; G A M E R - Assembly language joystick support for Turbo Pascal
;
;===========================================================================
;
; by Jeff Duntemann 12 February 1988
; with thanks to Ted Mirecki for additional insights
;
; From: COMPLETE TURBO PASCAL 5.0 by Jeff Duntemann
; Scott, Foresman & Co., Inc. 1988 ISBN 0-673-38355-5
;
;
; GAMER is a single assembly-language source file that contains both
; STICK.ASM and BUTTON.ASM, which are given separately elsewhere in
; COMPLETE TURBO PASCAL, 3E. The purpose of GAMER is to show how multiple
; assembly language procedures may be combined into a single machine-code
; module to lessen program clutter.
;
; The idea is to create a Turbo Pascal unit incorporating the routines in
; this module. The unit source file is GAMEBORD.PAS. The headers of both
; routines must be laid out in the interface section of GAMEBORD.PAS, and
; the .OBJ file containing the routines must be loaded into the
; implementation section of GAMEBORD.PAS using the $L compiler directive:
;
; INTERFACE
;
; FUNCTION Button(StickNumber,ButtonNumber : Integer) : Boolean;
;
; PROCEDURE Stick(StickNumber : Integer;
; VAR X : INTEGER;
; VAR Y : INTEGER);
;
; IMPLEMENTATION
;
; {$L GAMER}
; FUNCTION Button; EXTERNAL;
; PROCEDURE Stick; EXTERNAL;
;
;
;
; GAMEBORD.PAS is given elsewhere in COMPLETE TURBO PASCAL, 3E
;
;
; To reassemble/relink GAMER:
;-------------------------------------
; Assemble this file with MASM. "C>MASM GAMER;"
;
;
CODE SEGMENT BYTE PUBLIC ; THE SEGMENT IS BYTE-ALIGNED
ASSUME CS:CODE
PUBLIC BUTTON,STICK ; THE TWO ACCESSIBLE PROCS IN THIS MODULE
;===========================================================================
; B U T T O N - Function to return the state of the joystick buttons
;===========================================================================
;
; The full function header follows:
;
; FUNCTION BUTTON(StickNumber,ButtonNumber : Integer) : Boolean;
;
; StickNumber specifies which joystick to read from, and ButtonNumber
; specifies which of the two buttons on that joystick to read. If the
; specified button is down, BUTTON returns a Boolean value of TRUE.
;
; Yes, this is the long way 'round; assembly language is in no way required
; to read four bits from an ordinary 8088 I/O port. BUTTON exists only as
; practice in creating assembly language external functions.
;
; The button information is obtained by reading I/O port $201. The high
; four bits represent the state of the four buttons (two for each of the
; two possible joysticks) at the instant the port is read. A LOW bit
; represents a button DOWN. This is why the byte read from the port is
; inverted via NOT before the selected bit is tested.
;
; Here is a map of the button bits as returned by port $201:
;
; |7 6 5 4 3 2 1 0|
; | | | |
; | | | - - - - - - -> Button #1, joystick #1
; | | - - - - - - - -> Button #2, joystick #1
; | - - - - - - - - -> Button #1, joystick #2
; - - - - - - - - - -> Button #2, joystick #2
;
; Remember that the return value from this function is passed to the runtime
; code in the AL register.
;
;
; This structure defines the layout of BUTTON's parameters on the stack:
;
ONSTACK1 STRUC
OLDBP DW ? ;TOP OF STACK
RETADDR DD ? ;FAR RETURN ADDRESS
BTN_NO DW ? ;BUTTON NUMBER
STIK_NO DW ? ;STICK NUMBER
ONSTACK1 ENDS
BUTTON PROC FAR ;ALL PROCS IN A UNIT ARE FAR PROCS
PUSH BP ;SAVE PREVIOUS VALUE OF BP ON STACK
MOV BP,SP ;SP BECOMES NEW VALUE OF BP
;-------------------------------------------------------------------
; THE BULK OF THIS ROUTINE SETS UP A TEST MASK BY WHICH ONE SINGLE
; BIT OUT OF THE FOUR BUTTON BITS IS TESTED.
;-------------------------------------------------------------------
MOV BL,010H ;START WITH HIGH BIT IN BIT 4
CMP [BP].STIK_NO,2 ;ARE WE TESTING FOR JOYSTICK #2?
JNE WHICH ;IF NOT, GO ON TO TEST FOR WHICH BUTTON,
SHL BL,1 ; OTHERWISE SHIFT TWO POSITIONS LEFTWARD
SHL BL,1 ; SO THAT THE MASK IS ON BIT 6 FOR STICK 2
WHICH: CMP [BP].BTN_NO,2 ;ARE WE TESTING FOR BUTTON #2?
JNE READEM ;IF NOT, MASK IS CORRECT; GO READ PORT
SHL BL,1 ;OTHERWISE, SHIFT 1 BIT LEFT FOR BUTTON 2
;------------------------------------------------------------------------
; THE BIT MASK IS NOW CORRECT. HERE THE BUTTON BITS ARE READ FROM PORT
; $201 AND TESTED AGAINST THE MASK. NOTE THAT THE BITS AS READ FROM
; THE PORT MUST BE INVERTED SO THAT THE Z FLAG IS SET RATHER THAN CLEARED
; ON AN ACTIVE BUTTON BIT. (BITS ARE ACTIVE **LOW**, REMEMBER!)
;------------------------------------------------------------------------
READEM: MOV DX,0201H ;SET UP 16-BIT ADDRESS FOR PORT READ
IN AL,DX ;READ BUTTON BITS FROM PORT $201
NOT AL ;MUST INVERT BITS FOR PROPER SENSE
; OF THE Z FLAG AFTER TESTING
TEST AL,BL ;SEE IF THE DESIRED BIT IS HIGH;
JNZ PUSHED ;IF SO, BUTTON IS PUSHED,
MOV AL,0 ;SO MOVE BOOLEAN FALSE INTO AL
JMP BDONE ;AND GET OUT OF HERE
PUSHED: MOV AL,1 ;BUTTON DOWN; MOVE BOOLEAN TRUE INTO AL
BDONE: MOV SP,BP ;RESTORE PRIOR STACK POINTER & BP
POP BP ; IN CONVENTIONAL RETURN
RET 6
BUTTON ENDP
;===========================================================================
; S T I C K - Procedure to read either joystick
;===========================================================================
;
; The procedure header follows:
;
; PROCEDURE STICK(StickNumber : Integer VAR X,Y : Integer);
;
; StickNumber specifies which joystick to read from, and the X and Y
; parameters return integers proportional to the joystick's position
; at the moment the stick is sampled. These integers will vary from
; stick to stick depending on the resistance of the potentiometers
; used within the stick, but will typically from from 3 to 150.
;
; The IBM standard game controller board consists of two pairs of
; one-shots, which output a pulse when triggered by an I/O write to
; I/O port $201. The length of this pulse is determined by an RC
; time constant circuit the resistance portion of which is the
; potentiometer in the joystick. As the handle is moved around, the
; two potentiometers (one for X, one for Y) run up and back, changing
; resistance as they go.
;
; To read one of the two joysticks, a dummy value (which may be anything
; at all) is written to I/O port $201. Port $201 must then be polled
; continuously, incrementing a register at each polling event. When
; the bit corresponding to that stick's X or Y coordinate changes state,
; the count in the register is returned as that coordinate value at the
; time the stick was sampled.
;
; Here is a map of the joystick bits as returned by port $201:
;
; |7 6 5 4 3 2 1 0|
; | | | |
; | | | - - - - - - -> X coordinate, joystick #1
; | | - - - - - - - -> Y coordinate, joystick #1
; | - - - - - - - - -> X coordinate, joystick #2
; - - - - - - - - - -> Y coordinate, joystick #2
;
; One thing to keep in mind is that a bit goes LOW when sampled, and
; you must test for a HIGH on that bit to indicate that the one-shot has
; timed out.
;
;
;
; This structure defines STICK's parameters on the stack.
;
ONSTACK2 STRUC
OLDBP2 DW ? ;TOP OF STACK
RETADDR2 DD ? ;FAR RETURN ADDRESS
YADDR2 DD ? ;FAR ADDRESS OF X VALUE
XADDR2 DD ? ;FAR ADDRESS OF Y VALUE
STIK_NO2 DW ? ;STICK NUMBER
ONSTACK2 ENDS
; EQUATES FOR ONE-SHOT BITS FOR STICKS 1 & 2
STICK_X EQU 1
STICK_Y EQU 2
STICK PROC FAR
PUSH BP ;SAVE CALLER'S BP
MOV BP,SP ;STACK POINTER BECOMES NEW BP
PUSH DS
; GET THE X AXIS VALUE FIRST
MOV AH,STICK_X ; MOVE IN THE X TEST BIT
CMP [BP].STIK_NO2,2 ; SEE IF WE'RE TESTING STICK #1 OR #2
JNE TEST_X
SHL AH,1 ; SHIFT BIT NUMBERS 2 LEFT FOR STICK #2
SHL AH,1
TEST_X: MOV AL,1 ; INITIALIZE OUTPUT VALUE
MOV DX,201H ; SET PORT ADDRESS
MOV BX,0 ; AND KEEPING THE RUNUP COUNT IN BX
MOV CX,BX ; LOOP 64K TIMES MAX
OUT DX,AL ; TRIGGER THE ONE-SHOTS
AGAIN_X: IN AL,DX ; READ THE ONE-SHOT BITS
TEST AL,AH ; TEST FOR A HIGH BIT 0
JE DELAY ; WE'RE DONE IF BIT 0 IS HIGH
INC BX ; OTHERWISE INCREMENT BX AND LOOP AGAIN
LOOP AGAIN_X
MOV BX,-1 ; SET X=-1 IF NO RESPONSE
; DELAY HERE TO LET THE OTHER THREE PULSES MAX OUT
DELAY: MOV CX,512
WAIT: LOOP WAIT
; NOW WE GET THE Y AXIS VALUE
MOV AH,STICK_Y ; MOVE IN THE Y TEST BIT
CMP [BP].STIK_NO2,2 ; SEE IF WE'RE TESTING STICK #1 OR #2
JNE TEST_Y
SHL AH,1 ; SHIFT BIT NUMBERS 2 LEFT FOR STICK #2
SHL AH,1
TEST_Y: MOV SI,0 ; KEEP THE RUNUP COUNT FOR Y IN SI
MOV CX,SI ; SET LOOP LIMIT TO 64K
OUT DX,AL ; FIRE THE ONE-SHOTS AGAIN
AGAIN_Y: IN AL,DX ; READ THE ONE-SHOT BITS
TEST AL,AH ; TEST FOR A HIGH BIT 1
JE DONE ; WE'RE DONE IF BIT 1 IS HIGH
INC SI ; OTHERWISE INCREMENT SI AND LOOP AGAIN
LOOP AGAIN_Y
MOV SI,-1 ; SET Y=-1 IF NO RESPONSE
; MOVE RETURN VALUES FROM REGISTERS INTO VAR PARAMETERS X & Y
DONE: LDS DI,[BP].XADDR2 ;ADDR OF X INTO DS:DI
MOV [DI],BX ;X VALUE FROM BX TO DS:DI
LDS DI,[BP].YADDR2 ;DITTO FOR Y VALUE FROM SI
MOV [DI],SI
; IT'S OVER...NOW CLEAN UP THE STACK AND LEAVE
POP DS
MOV SP,BP ; CLEAN UP STACK AND LEAVE
POP BP ; RESTORE CALLER'S BP
RET 10
STICK ENDP
CODE ENDS
END